﻿using DxfLib;
using DxfOk.View;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using FolderBrowserEx;
using System.Windows.Forms;
using Config.Net;
using System.Windows.Input;
using DxfOk.Model;

namespace DxfOk.ViewModel
{
    public class MainViewModel : ObservableObject
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger
          (System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public static MainViewModel Main;

        public MainViewModel()
        {

            DxfItemViewModels = new ObservableCollection<DxfItemViewModel>();

            Main = this;
            LoadConfig();
        }

        private void LoadConfig()
        {
            LibConstants.settings = new ConfigurationBuilder<IOkSettings>()
             .UseIniFile(LibConstants.AppDataDxfOKIniFullName)
             .Build();

            log.Info("禁止单层列表:");
            foreach (string folder in LibConstants.settings.FuzzyFolders)
            {
                log.Info(folder);
            }

            log.Info("禁止单层列表:");
            foreach (string folder in LibConstants.settings.ProtectedSingleFolders)
            {
                log.Info(folder);
            }
            log.Info("禁止多层列表:");
            foreach (string folder in LibConstants.settings.ProtectedNestedFolders)
            {
                log.Info(folder);
            }
            ReScanFolders();
        }

        private void AddCopyText(string copiedText)
        {
            if (!DxfItemViewModel.regCopiedTextIndexedFolder.IsMatch(copiedText))
            {
                log.Info($"复制内容为{copiedText}，不符合格式，跳过。");
                return;
            }
            if (DxfItemViewModels.Any(x => x.CopiedText == copiedText))
            {
                log.Info($"复制内容为{copiedText}，重复，跳过。");
                return;
            }
            ReScanFolders();
            DxfItemViewModel dxfFolderViewModel = new DxfItemViewModel(copiedText);
            DxfType dxfType = dxfFolderViewModel.DxfType;
            if (
                ((dxfType & DxfType.FolderExist) == DxfType.FolderExist)
                || ((dxfType & DxfType.FolderExist) == DxfType.FolderExist))
            {
                DxfItemViewModels.Add(dxfFolderViewModel);
            }
            else
            {
                Message = $"{copiedText}不在模糊范围，添加行失败,{dxfType}";
            }
        }

        public void RenameFoldersUntilNoNew()
        {
            alreadyRenamedMarkerFiles = new HashSet<string>();
            Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
            File.AppendAllText(LibConstants.RenameFolderFails, $"开始重命名，{DateTime.Now}");
            while (RenameFoldersAccordingToMarkerFiles()) ;
            Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow;
            Message = "重命名结束。";
        }

        private HashSet<string> alreadyRenamedMarkerFiles;
        private bool RenameFoldersAccordingToMarkerFiles()
        {
            if (LibConstants.settings.FuzzyFolders == null || LibConstants.settings.FuzzyFolders.Length == 0)
                return true;
            bool hasNew = false;
            foreach (var folder in LibConstants.settings.FuzzyFolders)
            {
                foreach (var addFile in Directory.GetFiles(folder, LibConstants.AddOk, SearchOption.AllDirectories)
                    .OrderByDescending(f => Path.GetFullPath(f).Split(Path.DirectorySeparatorChar).Length))
                {
                    if (alreadyRenamedMarkerFiles.Contains(addFile))
                        continue;
                    string srcFolder = Path.GetDirectoryName(addFile);
                    string srcLastFolder = Path.GetFileName(srcFolder);
                    string baseFolder = Path.GetDirectoryName(srcFolder);
                    string desLastFolder = DxfUtils.SetOk(srcLastFolder);
                    string desFolder = Path.Combine(baseFolder, desLastFolder);
                    string desAddFile = Path.Combine(desFolder, LibConstants.AddOk);
                    try
                    {
                        Directory.Move(srcFolder, desFolder);
                        File.Delete(desAddFile);
                        alreadyRenamedMarkerFiles.Add(addFile);
                        log.Info($"重命名文件夹，增加ok：{srcFolder}-->{desFolder}");
                        hasNew = true;
                    }
                    catch (Exception ex)
                    {
                        File.AppendAllText(LibConstants.RenameFolderFails, $"{srcFolder}-->{desFolder}:{ex.Message}{Environment.NewLine}");
                        log.Error(ex.Message);
                    }
                    finally
                    {
                        alreadyRenamedMarkerFiles.Add(addFile);
                    }
                }

                foreach (var rmFile in Directory.GetFiles(folder, LibConstants.DelOk, SearchOption.AllDirectories)
    .OrderByDescending(f => Path.GetFullPath(f).Split(Path.DirectorySeparatorChar).Length))
                {
                    if (alreadyRenamedMarkerFiles.Contains(rmFile))
                        continue; string srcFolder = Path.GetDirectoryName(rmFile);
                    string srcLastFolder = Path.GetFileName(srcFolder);
                    string baseFolder = Path.GetDirectoryName(srcFolder);
                    string desLastFolder = DxfUtils.RemoveOk(srcLastFolder);
                    string desFolder = Path.Combine(baseFolder, desLastFolder);
                    string desRmFile = Path.Combine(desFolder, LibConstants.DelOk);
                    try
                    {
                        Directory.Move(srcFolder, desFolder);
                        File.Delete(desRmFile);
                        log.Info($"重命名文件夹，移除ok：{srcFolder}-->{desFolder}");
                        hasNew = true;
                    }
                    catch (Exception ex)
                    {
                        File.AppendAllText(LibConstants.RenameFolderFails, $"{srcFolder}-->{desFolder}:{ex.Message}{Environment.NewLine}");
                        log.Error(ex.Message);
                    }
                    finally
                    {
                        alreadyRenamedMarkerFiles.Add(rmFile);
                    }
                }
            }
            return hasNew;
        }

        private void RefreshCommands()
        {
            RefreshCommand.NotifyCanExecuteChanged();
            SetOkCommand.NotifyCanExecuteChanged();
            RemoveOkCommand.NotifyCanExecuteChanged();
            ClearCommand.NotifyCanExecuteChanged();
        }
        public void OnClipboardChanged()
        {
            // Handle your clipboard update here, debug logging example:
            if (System.Windows.Clipboard.ContainsText())
            {
                string copiedText = System.Windows.Clipboard.GetText();
                AddCopyText(copiedText);
                RefreshCommands();
            }
        }

        private ObservableCollection<DxfItemViewModel> dxfItemViewModels;
        public ObservableCollection<DxfItemViewModel> DxfItemViewModels
        {
            get => dxfItemViewModels;
            set => SetProperty(ref dxfItemViewModels, value);
        }


        private RelayCommand refreshCommand;
        public RelayCommand RefreshCommand => refreshCommand ?? (refreshCommand = new RelayCommand(ExecuteRefreshCommand, CanExecuteRefreshCommand));

        private bool CanExecuteRefreshCommand()
        {
            return !IsRefreshing && DxfItemViewModels.Any();
        }



        private bool isRefreshing;
        public bool IsRefreshing
        {
            get => isRefreshing;
            set => SetProperty(ref isRefreshing, value);
        }


        private void ExecuteRefreshCommand()
        {

            IsRefreshing = true;
            Message = $"已点刷新，请勿重复点击。";
            RefreshCommand.NotifyCanExecuteChanged();
            Task.Run(() =>
            {
                ReScanFolders();
                foreach (var dxfItemViewModel in DxfItemViewModels)
                {
                    dxfItemViewModel.InvalidateStatus();
                }
                Message = $"刷新完成。";
                IsRefreshing = false;
            });
        }


        private string message;
        public string Message
        {
            get => message;
            set => SetProperty(ref message, value);
        }

        private bool isBatchMode;
        private void ReScanFolders()
        {
            if (LibConstants.settings == null)
                return;
            if (isBatchMode && DxfUtils.AllRealFolders != null && DxfUtils.AllRealFolders.Count > 0)
                return;
            DxfUtils.AllRealFolders = new HashSet<string>(LibConstants.settings.FuzzyFolders);

            foreach (string fuzzyFolder in LibConstants.settings.FuzzyFolders)
            {
                if (Directory.Exists(fuzzyFolder))
                {
                    var folders = Directory.GetDirectories(fuzzyFolder, "*", SearchOption.AllDirectories);
                    DxfUtils.AllRealFolders.UnionWith(folders);
                    log.Info($"扫描了文件夹{fuzzyFolder},共有{folders.Length}个子文件夹。");
                }
                else
                {
                    log.Warn($"配置的模糊文件夹{fuzzyFolder}不存在！");
                }
            }


            //single

            DxfUtils.AllProtectedFolders = new HashSet<string>();

            foreach (string sigleFolder in LibConstants.settings.ProtectedSingleFolders)
            {
                if (Directory.Exists(sigleFolder))
                {
                    DxfUtils.AllProtectedFolders.Add(sigleFolder);
                }
                else if (sigleFolder.EndsWith("*"))
                {
                    string trimedStart = sigleFolder.TrimEnd('*');
                    log.Info($"单层禁止文件夹展开{trimedStart}下层");
                    DxfUtils.AllProtectedFolders.UnionWith(Directory.GetDirectories(trimedStart, "*", SearchOption.TopDirectoryOnly));
                }
                else
                {
                    log.Warn($"单层禁止文件夹不存在{sigleFolder}");
                }

            }

            //nested
            foreach (string sigleFolder in LibConstants.settings.ProtectedNestedFolders)
            {
                if (Directory.Exists(sigleFolder))
                {

                    log.Info($"多层禁止文件夹展开{sigleFolder}");
                    DxfUtils.AllProtectedFolders.UnionWith(Directory.GetDirectories(sigleFolder, "*", SearchOption.AllDirectories));
                }
                else
                {
                    log.Warn($"多层禁止文件夹不存在{sigleFolder}");
                }

            }

            //protect emtpy
            foreach (string sigleFolder in DxfUtils.AllRealFolders)
            {
                string? d = Path.GetFullPath(sigleFolder);
                if (!Directory.EnumerateFileSystemEntries(d).Any(x => !(x.EndsWith(LibConstants.AddOk)
                || x.EndsWith(LibConstants.DelOk)))
                    )
                {
                    log.Debug($"发现空文件夹{d}");
                    DxfUtils.AllProtectedFolders.Add(sigleFolder);
                    while (d != null && DxfUtils.AllRealFolders.Any(x => x == d || d.IsSubPathOf(x)))
                    {
                        //Debug.WriteLine(d);
                        log.Debug($"文件夹禁止单层空{d}");
                        DxfUtils.AllProtectedFolders.Add(d);
                        d = Path.GetDirectoryName(d);
                        //Debug.WriteLine(d);
                    }
                }
            }

            DxfUtils.AllRealFolders = DxfUtils.AllRealFolders.Except(DxfUtils.AllProtectedFolders).ToHashSet();
            File.WriteAllLines(LibConstants.ProtectedFoldersDetails, DxfUtils.AllProtectedFolders.OrderBy(x => x));
            File.WriteAllLines(LibConstants.FuzzyFoldersDetails, DxfUtils.AllRealFolders.OrderBy(x => x));
            string msg = $"模糊文件夹数量={DxfUtils.AllRealFolders.Count()},禁止文件夹数量={DxfUtils.AllProtectedFolders.Count()}";
            log.Info(msg);
            Message = msg;
        }

        //set ok

        private RelayCommand setokCommand;
        public RelayCommand SetOkCommand => setokCommand ?? (setokCommand = new RelayCommand(ExecuteSetOkCommand, CanExecuteSetOkCommand));

        private bool CanExecuteSetOkCommand()
        {
            return !IsSetOking;
        }



        private bool isSetingOkFolder;
        public bool IsSetOking
        {
            get => isSetingOkFolder;
            set => SetProperty(ref isSetingOkFolder, value);
        }



        private void ExecuteSetOkCommand()
        {

            IsSetOking = true;
            SetOkCommand.NotifyCanExecuteChanged();

            foreach (var dxfItemViewModel in DxfItemViewModels)
            {
                dxfItemViewModel.SetOk();
            }
            DxfUtils.CheckAllRealFoldersStatus();
            foreach (var dxfItemViewModel in DxfItemViewModels)
            {
                dxfItemViewModel.RefreshIfFolderExist();
            }
            Message = "增加ok完成";
            File.WriteAllLines(LibConstants.AllReadyFolders, DxfUtils.AllToAddOkFolders.OrderBy(x => x));
            File.WriteAllLines(LibConstants.AllNotReadyFolders, DxfUtils.AllToRmOkFolders.OrderBy(x => x));

            IsSetOking = false;
            SetOkCommand.NotifyCanExecuteChanged();
        }

        //rm  ok
        private RelayCommand removeokCommand;
        public RelayCommand RemoveOkCommand => removeokCommand ?? (removeokCommand = new RelayCommand(ExecuteRemoveOkCommand, CanExecuteRemoveOkCommand));

        private bool CanExecuteRemoveOkCommand()
        {
            return !IsRemoveOking;
        }



        private bool isRemovingOk;
        public bool IsRemoveOking
        {
            get => isRemovingOk;
            set => SetProperty(ref isRemovingOk, value);
        }



        private void ExecuteRemoveOkCommand()
        {

            IsRemoveOking = true;
            RemoveOkCommand.NotifyCanExecuteChanged();

            foreach (var dxfItemViewModel in DxfItemViewModels)
            {
                dxfItemViewModel.RemoveOk();
            }
            DxfUtils.CheckAllRealFoldersStatus();

            foreach (var dxfItemViewModel in DxfItemViewModels)
            {
                dxfItemViewModel.RefreshIfFolderExist();
            }

            DxfUtils.CheckAllRealFoldersStatus();
            Message = "移除ok完成";
            File.WriteAllLines(LibConstants.AllReadyFolders, DxfUtils.AllToAddOkFolders.OrderBy(x => x));
            File.WriteAllLines(LibConstants.AllNotReadyFolders, DxfUtils.AllToRmOkFolders.OrderBy(x => x));
            IsRemoveOking = false;
            RemoveOkCommand.NotifyCanExecuteChanged();

        }

        //clear
        private RelayCommand clearCommand;
        public RelayCommand ClearCommand => clearCommand ?? (clearCommand = new RelayCommand(ExecuteClearCommand, CanExecuteClearCommand));

        private bool CanExecuteClearCommand()
        {
            return DxfItemViewModels != null && DxfItemViewModels.Any();
        }



        private bool isClearing;
        public bool IsClearing
        {
            get => isClearing;
            set => SetProperty(ref isClearing, value);
        }



        private void ExecuteClearCommand()
        {

            IsClearing = true;
            ClearCommand.NotifyCanExecuteChanged();
            DxfItemViewModels.Clear();
            Message = "清空完成";
            IsClearing = false;
            ClearCommand.NotifyCanExecuteChanged();

        }

        //browsefile
        private RelayCommand browseFileCommand;
        public RelayCommand BrowseFileCommand => browseFileCommand ?? (browseFileCommand = new RelayCommand(ExecuteBrowseFileCommand, CanExecuteBrowseFileCommand));

        private bool CanExecuteBrowseFileCommand()
        {
            return !IsBrowseFileing;
        }



        private bool isBrowsingFolder;
        public bool IsBrowseFileing
        {
            get => isBrowsingFolder;
            set => SetProperty(ref isBrowsingFolder, value);
        }
        Regex reg = new Regex(@"【\d\d\d】\s*.+", RegexOptions.Compiled);

        private void ExecuteBrowseFileCommand()
        {

            IsBrowseFileing = true;
            BrowseFileCommand.NotifyCanExecuteChanged();

            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Title = "浏览文件以便批量导入";
            openFileDialog.Filter = "dxf文件(*.dxf)|*.dxf|txt文件(*.txt)|*.txt";
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
                string dxfFullName = openFileDialog.FileName;
                log.Info($"准备批量导入{dxfFullName}");
                Message = $"准备批量导入{dxfFullName}";
                string[] lines = new string[0];
                try
                {
                    lines = File.ReadAllLines(dxfFullName, Encoding.GetEncoding("gb2312"));

                }
                catch (Exception ex)
                {
                    log.Error(ex.Message);
                    Message = ex.Message;
                    return;
                }
                finally
                {
                    Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow;
                }
                var copies = lines.Where(line => reg.IsMatch(line));
                isBatchMode = true;
                foreach (string line in copies)
                {
                    AddCopyText(line);
                    //log.Debug(line.Trim());
                }
                RefreshCommands();
                isBatchMode = false;
                Message = $"完成批量导入{dxfFullName}，共{copies.Count()}条";
                Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow;

            }
            IsBrowseFileing = false;
            BrowseFileCommand.NotifyCanExecuteChanged();

        }

    }
}
